﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AdaptiveDeNet.CSV;
using AdaptiveDeNet.RAND;
using System.Threading.Tasks;
using System.Threading;
using System.Diagnostics;

namespace AdaptiveDeNet.DifferentialEvolution.MultiThreaded
{
    public partial class Optimizer
    {
        public CEC14Result jDE(double[] lowerBound,
             double[] upperBound, int maxEvals, int dim, int N, double myEpps, Queue<double> FESMultipliers, double fX, int funcNum, double p1, double p2)
        {
            mre = new ManualResetEvent(false);
            countdown = new CountdownEvent(threadCount);
            outerCountdown = new CountdownEvent(threadCount);

            lockers = new ManualResetEventSlim[threadCount];

            mreslis = new ManualResetEventSlim[threadCount];

            condition = true;

            CEC14Result result = new CEC14Result();

            for (int i = 0; i < lockers.Length; i++)
            {
                lockers[i] = new ManualResetEventSlim(false);
            }


            for (int i = 0; i < mreslis.Length; i++)
            {
                mreslis[i] = new ManualResetEventSlim(false);
            }

            RngStream stream = new RngStream();
            long seed = DateTime.Now.Ticks & Int32.MaxValue;
            RngStream.setPackageSeed(new long[] { seed, seed, seed, seed, seed, seed });

            this.nRand = new Rand();

            double Fmin = double.MaxValue;
            double Fmax = double.MinValue;

            //row, col
            //double[] trialsFevals1 = new double[N];

            double[] uBlBDiff = new double[dim];

            for (int i = 0; i < dim; i++)
            {
                uBlBDiff[i] = upperBound[i] - lowerBound[i];
            }

            //Fmax = Common.FindMax(fEvals);
            int popEvals = N;

            //
            //
            //
            //mainPopHolder
            int padding = 16;
            int spacing = 16;

            //pointers
            int[] populationPointers = new int[N];
            int[] fitnessPointers = new int[N];





            double[] mainPopHolder = new double[padding + ((dim + 1) * N) + (threadCount * spacing)];
            double[] trialsPopHolder = new double[padding + ((dim + 1) * N) + (threadCount * spacing)];

            int helper = 0;

            for (int threadActual = 0; threadActual < threadCount; threadActual++)
            {
                var max = N * (threadActual + 1) / threadCount;

                double[] temp = new double[dim];
                double fEvalInner = 0;

                for (int i = N * threadActual / threadCount; i < max; i++)
                {
                    //member vector initialization
                    int start = padding + i * (dim + 1) + threadActual * spacing;
                    int end = start + dim;

                    populationPointers[helper] = start;
                    fitnessPointers[helper] = end;

                    for (int j = start, forDiff = 0; j < end; j++, forDiff++)
                    {
                        temp[forDiff] = nRand.NextDouble() * uBlBDiff[forDiff] + lowerBound[forDiff];
                    }

                    fEvalInner = fEval.Feval(temp); //evaluation
                    if (fEvalInner < Fmin) Fmin = fEvalInner; //is fMin ?


                    Array.Copy(temp, 0, mainPopHolder, start, dim); // temp -> mainPopHolder
                    mainPopHolder[end] = fEvalInner; // fEval -> mainPopHolder

                    helper++;
                }
            }


            int[] CrPointers = new int[N];

            double[] fCrMain = new double[padding + (2 * N) + (threadCount * spacing)];
            double[] fCrTrial = new double[padding + (2 * N) + (threadCount * spacing)];

            int CrHelper = 0;

            for (int threadActual = 0; threadActual < threadCount; threadActual++)
            {
                var max = padding + (2 * N) * ((threadActual) + 1) / threadCount + (threadActual * spacing);

                for (int i = padding + (2 * N) * (threadActual) / threadCount + (threadActual * spacing); i < max; i++)
                {

                    CrPointers[CrHelper] = i;

                    fCrMain[i] = nRand.NextDouble();
                    ++i;
                    fCrMain[i] = nRand.NextDouble();

                    CrHelper++;
                }

            }

            Fmax = this.FindMax(mainPopHolder, fitnessPointers);
            Fmin = this.FindMin(mainPopHolder, fitnessPointers);

            //
            //

            long[] affinity = new long[threadCount];

            affinity[0] = 0x0001;
            affinity[1] = 0x0004;

            for (int k = 0; k < threadCount; k++)
            {
                int iThread = k;

                ThreadPool.QueueUserWorkItem((st) =>
                {
                    lockers[iThread] = new ManualResetEventSlim(true);

                    int start = N * iThread / threadCount;
                    int end = N * (iThread + 1) / threadCount;
                    int n1 = N - 1;
                    int dim1 = dim - 1;
                    RngStream localStream = new RngStream();

                    uint unmanagedId = GetCurrentThreadId();

                    ProcessThread myThread = (from ProcessThread entry in Process.GetCurrentProcess().Threads
                                              where entry.Id == unmanagedId
                                              select entry).First();

                    myThread.ProcessorAffinity = (IntPtr)affinity[iThread];

                    CEC14Lib.CEC14func localFunc = new CEC14Lib.CEC14func(30, funcNum);

                    double[] temp = new double[dim];

                    double innerFEval = 0;
                    int i = start;

                    double[] randJ = new double[4]; // RAND J

                    double trialCr;
                    double trialF;

                    countdown.Signal();

                    do
                    {

                        lockers[iThread].Wait();
                        lockers[iThread].Reset();



                        for (i = start; i < end; i++)
                        {
                            //adaptation fo Cr a F
                            trialCr = fCrMain[CrPointers[i]];
                            trialF = fCrMain[CrPointers[i] + 1];

                            for (int j = 0; j < 4; j++) randJ[j] = localStream.randU01();

                            if (randJ[1] < p1) trialCr = 0.1 + randJ[0] * 0.9;
                            if (randJ[3] < p2) trialF = randJ[2];

                            //
                            //endblock

                            int r0Index = localStream.randInt(0, n1);
                            int r1Index = localStream.randInt(0, n1);
                            int r2Index = localStream.randInt(0, n1);

                            while (i == r0Index) r0Index = localStream.randInt(0, n1);

                            while (i == r1Index || r0Index == r1Index) r1Index = localStream.randInt(0, n1);

                            while (i == r2Index || r0Index == r2Index || r1Index == r2Index) r2Index = localStream.randInt(0, n1);

                            int jrand = localStream.randInt(0, dim1);

                            int innerStart = padding + i * (dim + 1) + iThread * spacing;
                            int innerEnd = innerStart + dim;

                            int popPtr = i;

                            for (int j = innerStart, jPtr = 0; j < innerEnd; j++, jPtr++)
                            {
                                //krizeni
                                if (localStream.randU01() <= trialCr || jPtr == jrand)
                                {
                                    temp[jPtr] = mainPopHolder[populationPointers[r0Index] + jPtr] +
                                        trialF * (mainPopHolder[populationPointers[r1Index] + jPtr] -
                                        mainPopHolder[populationPointers[r2Index] + jPtr]);

                                    if (temp[jPtr] < lowerBound[jPtr] || temp[jPtr] > upperBound[jPtr])
                                    {
                                        temp[jPtr] = Common.Common.Zrdcad(temp[jPtr],
                                            lowerBound[jPtr], upperBound[jPtr]);
                                    }
                                }
                                else
                                {
                                    temp[jPtr] = mainPopHolder[j];
                                }

                            }

                            //Array.Copy(temp, 0, trialsPopHolder, innerStart, dim);
                            //Array.Copy(trialsPopHolder, innerStart, temp, 0, dim);
                            //Buffer.BlockCopy(Q, innerStart, temp, 0, dim * sizeof(double));

                            innerFEval = localFunc.FEval(temp, 30, funcNum);

                            if (innerFEval <= mainPopHolder[innerEnd])
                            {
                                trialsPopHolder[innerEnd] = innerFEval;
                                Array.Copy(temp, 0, trialsPopHolder, innerStart, dim);

                                fCrTrial[CrPointers[i]] = trialCr;
                                fCrTrial[CrPointers[i] + 1] = trialF;

                                //CR and F copy

                            }//succesful trial
                            else
                            {
                                trialsPopHolder[innerEnd] = mainPopHolder[innerEnd];
                                Array.Copy(mainPopHolder, innerStart, trialsPopHolder, innerStart, dim);

                                fCrTrial[CrPointers[i]] = fCrMain[CrPointers[i]];
                                fCrTrial[CrPointers[i] + 1] = fCrMain[CrPointers[i] + 1];

                                //CR and F copy
                            }

                        }


                        mreslis[iThread].Set();
                        //countdown.Signal();

                    } while (condition);

                    outerCountdown.Signal();

                });
            }

            countdown.Wait();

            while (popEvals < maxEvals && (Fmin - fX) > 10E-8)
            {
                for (int i = 0; i < threadCount; i++)
                {
                    lockers[i].Set();
                }

                for (int i = 0; i < mreslis.Length; i++)
                {

                    mreslis[i].Wait();
                    mreslis[i].Reset();
                }

                double[] pom;

                pom = mainPopHolder;
                mainPopHolder = trialsPopHolder;
                trialsPopHolder = pom;

                pom = fCrMain;
                fCrMain = fCrTrial;
                fCrTrial = pom;

                Fmax = this.FindMax(mainPopHolder, fitnessPointers);
                Fmin = this.FindMin(mainPopHolder, fitnessPointers);

                popEvals += N;

                if (popEvals == (FESMultipliers.Peek() * maxEvals))
                {
                    result.Records.Add(Fmin - fX);
                    FESMultipliers.Dequeue();
                }

                //countdown.Reset(2);
            }

            condition = false;
            //Monitor.PulseAll(locker);
            //countdown.Wait();

            for (int i = 0; i < lockers.Length; i++)
            {
                lockers[i].Set();
            }

            outerCountdown.Wait();

            result.FuncEvals = popEvals;


            return result;
        }

        /// <summary>
        /// jDE - Differential Evolution with self-adaptation of control parameters, tries to find global minimum point of given function
        /// </summary>
        /// <param name="lowerBound">Lower bound vector</param>
        /// <param name="upperBound">Upper bound vector</param>
        /// <param name="maxEvals">maximum evaluations of objective function</param>
        /// <param name="dim">dimension of problem</param>
        /// <param name="N">size of population</param>
        /// <param name="myEpps">small nonnegative value, when (Fmax - Fmin) is smaller then myEpps, the termination criteria are satisfied</param>
        /// <param name="pi1">probability of mutation - scale factor F</param>
        /// <param name="pi2">probability of mutation - crossover probability Cr</param>
        /// <returns></returns>
        public Result jDE(double[] lowerBound,
             double[] upperBound, int maxEvals, int dim, int N, double myEpps, double p1, double p2)
        {
            mre = new ManualResetEvent(false);
            countdown = new CountdownEvent(threadCount);
            outerCountdown = new CountdownEvent(threadCount);

            lockers = new ManualResetEventSlim[threadCount];

            mreslis = new ManualResetEventSlim[threadCount];

            condition = true;

            for (int i = 0; i < lockers.Length; i++)
            {
                lockers[i] = new ManualResetEventSlim(false);
            }


            for (int i = 0; i < mreslis.Length; i++)
            {
                mreslis[i] = new ManualResetEventSlim(false);
            }

            RngStream stream = new RngStream();
            long seed = DateTime.Now.Ticks & Int32.MaxValue;
            RngStream.setPackageSeed(new long[] { seed, seed, seed, seed, seed, seed });

            this.nRand = new Rand();

            double Fmin = double.MaxValue;
            double Fmax = double.MinValue;

            //row, col
            //double[] trialsFevals1 = new double[N];

            double[] uBlBDiff = new double[dim];

            for (int i = 0; i < dim; i++)
            {
                uBlBDiff[i] = upperBound[i] - lowerBound[i];
            }

            //Fmax = Common.FindMax(fEvals);
            int popEvals = N;

            //
            //
            //
            //mainPopHolder
            int padding = 16;
            int spacing = 16;

            //pointers
            int[] populationPointers = new int[N];
            int[] fitnessPointers = new int[N];





            double[] mainPopHolder = new double[padding + ((dim + 1) * N) + (threadCount * spacing)];
            double[] trialsPopHolder = new double[padding + ((dim + 1) * N) + (threadCount * spacing)];

            int helper = 0;

            for (int threadActual = 0; threadActual < threadCount; threadActual++)
            {
                var max = N * (threadActual + 1) / threadCount;

                double[] temp = new double[dim];
                double fEvalInner = 0;

                for (int i = N * threadActual / threadCount; i < max; i++)
                {
                    //member vector initialization
                    int start = padding + i * (dim + 1) + threadActual * spacing;
                    int end = start + dim;

                    populationPointers[helper] = start;
                    fitnessPointers[helper] = end;

                    for (int j = start, forDiff = 0; j < end; j++, forDiff++)
                    {
                        temp[forDiff] = nRand.NextDouble() * uBlBDiff[forDiff] + lowerBound[forDiff];
                    }

                    fEvalInner = fEval.Feval(temp); //evaluation
                    if (fEvalInner < Fmin) Fmin = fEvalInner; //is fMin ?


                    Array.Copy(temp, 0, mainPopHolder, start, dim); // temp -> mainPopHolder
                    mainPopHolder[end] = fEvalInner; // fEval -> mainPopHolder

                    helper++;
                }
            }


            int[] CrPointers = new int[N];

            double[] fCrMain = new double[padding + (2 * N) + (threadCount * spacing)];
            double[] fCrTrial = new double[padding + (2 * N) + (threadCount * spacing)];

            int CrHelper = 0;

            for (int threadActual = 0; threadActual < threadCount; threadActual++)
            {
                var max = padding + (2 * N) * ((threadActual) + 1) / threadCount + (threadActual * spacing);

                for (int i = padding + (2 * N) * (threadActual) / threadCount + (threadActual * spacing); i < max; i++)
                {

                    CrPointers[CrHelper] = i;

                    fCrMain[i] = nRand.NextDouble();
                    ++i;
                    fCrMain[i] = nRand.NextDouble();

                    CrHelper++;
                }

            }

            Fmax = this.FindMax(mainPopHolder, fitnessPointers);
            Fmin = this.FindMin(mainPopHolder, fitnessPointers);

            for (int k = 0; k < threadCount; k++)
            {
                int iThread = k;

                ThreadPool.QueueUserWorkItem((st) =>
                {
                    lockers[iThread] = new ManualResetEventSlim(true);

                    int start = N * iThread / threadCount;
                    int end = N * (iThread + 1) / threadCount;
                    int n1 = N - 1;
                    int dim1 = dim - 1;
                    RngStream localStream = new RngStream();

                    double[] temp = new double[dim];

                    double innerFEval = 0;
                    int i = start;

                    double[] randJ = new double[4]; // RAND J

                    double trialCr;
                    double trialF;

                    countdown.Signal();

                    do
                    {

                        lockers[iThread].Wait();
                        lockers[iThread].Reset();



                        for (i = start; i < end; i++)
                        {
                            //adaptation fo Cr a F
                            trialCr = fCrMain[CrPointers[i]];
                            trialF = fCrMain[CrPointers[i] + 1];

                            for (int j = 0; j < 4; j++) randJ[j] = localStream.randU01();

                            if (randJ[1] < p1) trialCr = 0.1 + randJ[0] * 0.9;
                            if (randJ[3] < p2) trialF = randJ[2];

                            //
                            //endblock

                            int r0Index = localStream.randInt(0, n1);
                            int r1Index = localStream.randInt(0, n1);
                            int r2Index = localStream.randInt(0, n1);

                            while (i == r0Index) r0Index = localStream.randInt(0, n1);

                            while (i == r1Index || r0Index == r1Index) r1Index = localStream.randInt(0, n1);

                            while (i == r2Index || r0Index == r2Index || r1Index == r2Index) r2Index = localStream.randInt(0, n1);

                            int jrand = localStream.randInt(0, dim1);

                            int innerStart = padding + i * (dim + 1) + iThread * spacing;
                            int innerEnd = innerStart + dim;

                            int popPtr = i;

                            for (int j = innerStart, jPtr = 0; j < innerEnd; j++, jPtr++)
                            {
                                //krizeni
                                if (localStream.randU01() <= trialCr || jPtr == jrand)
                                {
                                    temp[jPtr] = mainPopHolder[populationPointers[r0Index] + jPtr] +
                                        trialF * (mainPopHolder[populationPointers[r1Index] + jPtr] -
                                        mainPopHolder[populationPointers[r2Index] + jPtr]);

                                    if (temp[jPtr] < lowerBound[jPtr] || temp[jPtr] > upperBound[jPtr])
                                    {
                                        temp[jPtr] = Common.Common.Zrdcad(temp[jPtr],
                                            lowerBound[jPtr], upperBound[jPtr]);
                                    }
                                }
                                else
                                {
                                    temp[jPtr] = mainPopHolder[j];
                                }

                            }

                            innerFEval = fEval.Feval(temp);

                            if (innerFEval <= mainPopHolder[innerEnd])
                            {
                                trialsPopHolder[innerEnd] = innerFEval;
                                Array.Copy(temp, 0, trialsPopHolder, innerStart, dim);

                                fCrTrial[CrPointers[i]] = trialCr;
                                fCrTrial[CrPointers[i] + 1] = trialF;

                                //CR and F copy

                            }//succesful trial
                            else
                            {
                                trialsPopHolder[innerEnd] = mainPopHolder[innerEnd];
                                Array.Copy(mainPopHolder, innerStart, trialsPopHolder, innerStart, dim);

                                fCrTrial[CrPointers[i]] = fCrMain[CrPointers[i]];
                                fCrTrial[CrPointers[i] + 1] = fCrMain[CrPointers[i] + 1];

                                //CR and F copy
                            }

                        }


                        mreslis[iThread].Set();
                        //countdown.Signal();

                    } while (condition);

                    outerCountdown.Signal();

                });
            }

            countdown.Wait();

            while (popEvals < maxEvals && (Fmax - Fmin) > myEpps)
            {
                for (int i = 0; i < threadCount; i++)
                {
                    lockers[i].Set();
                }

                for (int i = 0; i < mreslis.Length; i++)
                {

                    mreslis[i].Wait();
                    mreslis[i].Reset();
                }

                double[] pom;

                pom = mainPopHolder;
                mainPopHolder = trialsPopHolder;
                trialsPopHolder = pom;

                pom = fCrMain;
                fCrMain = fCrTrial;
                fCrTrial = pom;

                Fmax = this.FindMax(mainPopHolder, fitnessPointers);
                Fmin = this.FindMin(mainPopHolder, fitnessPointers);

                popEvals += N;

            }

            condition = false;

            for (int i = 0; i < lockers.Length; i++)
            {
                lockers[i].Set();
            }

            outerCountdown.Wait();

            Result result = new Result();

            result.FuncEvals = popEvals;
            result.Fmin = Fmin;
            result.Point = Common.Common.GetBestMember(mainPopHolder, fitnessPointers, N, dim);


            return result;
        }
        /// <summary>
        /// jDE - Differential Evolution with self-adaptation of control parameters, tries to find global minimum point of given function
        /// </summary>
        /// <param name="function">objective function</param>
        /// <param name="lowerBound">Lower bound vector</param>
        /// <param name="upperBound">Upper bound vector</param>
        /// <param name="maxEvals">maximum evaluations of objective function</param>
        /// <param name="dim">dimension of problem</param>
        /// <param name="N">size of population</param>
        /// <param name="myEpps">small nonnegative value, when (Fmax - Fmin) is smaller then myEpps, the termination criteria are satisfied</param>
        /// <param name="pi1">probability of mutation - scale factor F</param>
        /// <param name="pi2">probability of mutation - crossover probability Cr</param>
        /// <returns></returns>
        public Result jDE(Func<double[], double> function, double[] lowerBound,
             double[] upperBound, int maxEvals, int dim, int N, double myEpps, double p1, double p2)
        {
            mre = new ManualResetEvent(false);
            countdown = new CountdownEvent(threadCount);
            outerCountdown = new CountdownEvent(threadCount);

            lockers = new ManualResetEventSlim[threadCount];

            mreslis = new ManualResetEventSlim[threadCount];

            condition = true;

            for (int i = 0; i < lockers.Length; i++)
            {
                lockers[i] = new ManualResetEventSlim(false);
            }


            for (int i = 0; i < mreslis.Length; i++)
            {
                mreslis[i] = new ManualResetEventSlim(false);
            }

            RngStream stream = new RngStream();
            long seed = DateTime.Now.Ticks & Int32.MaxValue;
            RngStream.setPackageSeed(new long[] { seed, seed, seed, seed, seed, seed });

            this.nRand = new Rand();

            double Fmin = double.MaxValue;
            double Fmax = double.MinValue;

            //row, col
            //double[] trialsFevals1 = new double[N];

            double[] uBlBDiff = new double[dim];

            for (int i = 0; i < dim; i++)
            {
                uBlBDiff[i] = upperBound[i] - lowerBound[i];
            }

            //Fmax = Common.FindMax(fEvals);
            int popEvals = N;

            //
            //
            //
            //mainPopHolder
            int padding = 16;
            int spacing = 16;

            //pointers
            int[] populationPointers = new int[N];
            int[] fitnessPointers = new int[N];





            double[] mainPopHolder = new double[padding + ((dim + 1) * N) + (threadCount * spacing)];
            double[] trialsPopHolder = new double[padding + ((dim + 1) * N) + (threadCount * spacing)];

            int helper = 0;

            for (int threadActual = 0; threadActual < threadCount; threadActual++)
            {
                var max = N * (threadActual + 1) / threadCount;

                double[] temp = new double[dim];
                double fEvalInner = 0;

                for (int i = N * threadActual / threadCount; i < max; i++)
                {
                    //member vector initialization
                    int start = padding + i * (dim + 1) + threadActual * spacing;
                    int end = start + dim;

                    populationPointers[helper] = start;
                    fitnessPointers[helper] = end;

                    for (int j = start, forDiff = 0; j < end; j++, forDiff++)
                    {
                        temp[forDiff] = nRand.NextDouble() * uBlBDiff[forDiff] + lowerBound[forDiff];
                    }

                    fEvalInner = function.Invoke(temp); //evaluation
                    if (fEvalInner < Fmin) Fmin = fEvalInner; //is fMin ?


                    Array.Copy(temp, 0, mainPopHolder, start, dim); // temp -> mainPopHolder
                    mainPopHolder[end] = fEvalInner; // fEval -> mainPopHolder

                    helper++;
                }
            }


            int[] CrPointers = new int[N];

            double[] fCrMain = new double[padding + (2 * N) + (threadCount * spacing)];
            double[] fCrTrial = new double[padding + (2 * N) + (threadCount * spacing)];

            int CrHelper = 0;

            for (int threadActual = 0; threadActual < threadCount; threadActual++)
            {
                var max = padding + (2 * N) * ((threadActual) + 1) / threadCount + (threadActual * spacing);

                for (int i = padding + (2 * N) * (threadActual) / threadCount + (threadActual * spacing); i < max; i++)
                {

                    CrPointers[CrHelper] = i;

                    fCrMain[i] = nRand.NextDouble();
                    ++i;
                    fCrMain[i] = nRand.NextDouble();

                    CrHelper++;
                }

            }

            Fmax = this.FindMax(mainPopHolder, fitnessPointers);
            Fmin = this.FindMin(mainPopHolder, fitnessPointers);

            for (int k = 0; k < threadCount; k++)
            {
                int iThread = k;

                ThreadPool.QueueUserWorkItem((st) =>
                {
                    lockers[iThread] = new ManualResetEventSlim(true);

                    int start = N * iThread / threadCount;
                    int end = N * (iThread + 1) / threadCount;
                    int n1 = N - 1;
                    int dim1 = dim - 1;
                    RngStream localStream = new RngStream();

                    double[] temp = new double[dim];

                    double innerFEval = 0;
                    int i = start;

                    double[] randJ = new double[4]; // RAND J

                    double trialCr;
                    double trialF;

                    countdown.Signal();

                    do
                    {

                        lockers[iThread].Wait();
                        lockers[iThread].Reset();



                        for (i = start; i < end; i++)
                        {
                            //adaptation fo Cr a F
                            trialCr = fCrMain[CrPointers[i]];
                            trialF = fCrMain[CrPointers[i] + 1];

                            for (int j = 0; j < 4; j++) randJ[j] = localStream.randU01();

                            if (randJ[1] < p1) trialCr = 0.1 + randJ[0] * 0.9;
                            if (randJ[3] < p2) trialF = randJ[2];

                            //
                            //endblock

                            int r0Index = localStream.randInt(0, n1);
                            int r1Index = localStream.randInt(0, n1);
                            int r2Index = localStream.randInt(0, n1);

                            while (i == r0Index) r0Index = localStream.randInt(0, n1);

                            while (i == r1Index || r0Index == r1Index) r1Index = localStream.randInt(0, n1);

                            while (i == r2Index || r0Index == r2Index || r1Index == r2Index) r2Index = localStream.randInt(0, n1);

                            int jrand = localStream.randInt(0, dim1);

                            int innerStart = padding + i * (dim + 1) + iThread * spacing;
                            int innerEnd = innerStart + dim;

                            int popPtr = i;

                            for (int j = innerStart, jPtr = 0; j < innerEnd; j++, jPtr++)
                            {
                                //krizeni
                                if (localStream.randU01() <= trialCr || jPtr == jrand)
                                {
                                    temp[jPtr] = mainPopHolder[populationPointers[r0Index] + jPtr] +
                                        trialF * (mainPopHolder[populationPointers[r1Index] + jPtr] -
                                        mainPopHolder[populationPointers[r2Index] + jPtr]);

                                    if (temp[jPtr] < lowerBound[jPtr] || temp[jPtr] > upperBound[jPtr])
                                    {
                                        temp[jPtr] = Common.Common.Zrdcad(temp[jPtr],
                                            lowerBound[jPtr], upperBound[jPtr]);
                                    }
                                }
                                else
                                {
                                    temp[jPtr] = mainPopHolder[j];
                                }

                            }

                            innerFEval = function.Invoke(temp);

                            if (innerFEval <= mainPopHolder[innerEnd])
                            {
                                trialsPopHolder[innerEnd] = innerFEval;
                                Array.Copy(temp, 0, trialsPopHolder, innerStart, dim);

                                fCrTrial[CrPointers[i]] = trialCr;
                                fCrTrial[CrPointers[i] + 1] = trialF;

                                //CR and F copy

                            }//succesful trial
                            else
                            {
                                trialsPopHolder[innerEnd] = mainPopHolder[innerEnd];
                                Array.Copy(mainPopHolder, innerStart, trialsPopHolder, innerStart, dim);

                                fCrTrial[CrPointers[i]] = fCrMain[CrPointers[i]];
                                fCrTrial[CrPointers[i] + 1] = fCrMain[CrPointers[i] + 1];

                                //CR and F copy
                            }

                        }


                        mreslis[iThread].Set();
                        //countdown.Signal();

                    } while (condition);

                    outerCountdown.Signal();

                });
            }

            countdown.Wait();

            while (popEvals < maxEvals && (Fmax - Fmin) > myEpps)
            {
                for (int i = 0; i < threadCount; i++)
                {
                    lockers[i].Set();
                }

                for (int i = 0; i < mreslis.Length; i++)
                {

                    mreslis[i].Wait();
                    mreslis[i].Reset();
                }

                double[] pom;

                pom = mainPopHolder;
                mainPopHolder = trialsPopHolder;
                trialsPopHolder = pom;

                pom = fCrMain;
                fCrMain = fCrTrial;
                fCrTrial = pom;

                Fmax = this.FindMax(mainPopHolder, fitnessPointers);
                Fmin = this.FindMin(mainPopHolder, fitnessPointers);

                popEvals += N;

            }

            condition = false;

            for (int i = 0; i < lockers.Length; i++)
            {
                lockers[i].Set();
            }

            outerCountdown.Wait();

            Result result = new Result();

            result.FuncEvals = popEvals;
            result.Fmin = Fmin;
            result.Point = Common.Common.GetBestMember(mainPopHolder, fitnessPointers, N, dim);


            return result;
        }
    }
}
